package com.itcoon.cloud.framework.transform.assemble.assembler.inter;

import com.itcoon.cloud.framework.transform.assemble.handler.AssembleHandlerComposite;
import com.itcoon.cloud.framework.transform.definition.InjectDefinition;
import com.itcoon.cloud.framework.transform.definition.ModelDefinition;
import com.itcoon.cloud.framework.transform.definition.ModelPropertyDefinition;
import com.itcoon.cloud.framework.transform.pool.AssembleBeanHolder;
import com.itcoon.cloud.framework.transform.utils.TransformServiceUtils;
import com.itcoon.cloud.framework.utils.MethodUtil;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ModelPropertyAssembler implements MethodAssembler {

    @Autowired
    private AssembleHandlerComposite composite;

    @Override
    public boolean support(Class<?> targetClass, Object source,  Method method, String[] ignoreProperties) {
        if (method.isDefault()) {
            return false;
        }
        ModelDefinition md = AssembleBeanHolder.getInstance().getModelDefinition(targetClass, source);
        if (md == null) {
            return false;
        }
        Optional<ModelPropertyDefinition> mpdOp  = md.getPropertyDefinitions().stream().filter(mpd -> mpd.getTargetAttribute().equals(MethodUtil.getMethodAttribute(method))).findAny();
        return mpdOp.isPresent();
    }

    @Override
    public <T, R> Object assemble(T source, Class<R> targetClass, Object proxy, Method method, String[] ignoreProperties, List<InjectDefinition> injectInfos, Object[] args) throws Exception {
        // 查找关联的mapping关联，拷贝赋值
        ModelDefinition md = AssembleBeanHolder.getInstance().getModelDefinition(targetClass, source);
        List<ModelPropertyDefinition> mpds = md.getPropertyDefinitions();
        Optional<ModelPropertyDefinition> mpdOp;
        Type returnType;
        if(targetClass.isInterface()){
            returnType = method.getGenericReturnType();
            mpdOp = mpds.stream().filter(mpd -> mpd.getTargetGetter().equals(method)).findAny();
        }else{
            returnType = method.getGenericParameterTypes()[0];
            mpdOp = mpds.stream().filter(mpd -> mpd.getTargetSetter()!= null && mpd.getTargetSetter().equals(method)).findAny();
        }
        ModelPropertyDefinition mpd = mpdOp.get();
        Method originGetter = mpd.getOriginGetter();
        if(originGetter == null){
            return null;
        }

        String methodAttribute = MethodUtil.getMethodAttribute(originGetter);
        // 根据嵌套获取源对象的域值

        List<String> cascadeIgnoreProperties = new ArrayList<>();
        for (String ignoreProperty : ignoreProperties) {
            if(ignoreProperty.contains(".")){
                String firstData = ignoreProperty.substring(0, ignoreProperty.indexOf("."));
                if(firstData.equals(methodAttribute)){
                    cascadeIgnoreProperties.add(ignoreProperty.substring(ignoreProperty.indexOf(".") + 1));
                }
            }else if (ignoreProperty.equals(methodAttribute)){
                return null;
            }
        }
        String value = mpd.getOriginAttribute();
        Object cascadeObj = TransformServiceUtils.getBelongFromValue(source, value);
        Object originGetterValue = cascadeObj == null ? null : originGetter.invoke(cascadeObj);
        // 执行assemble编集
        if (originGetterValue != null) {
            String targetAttribute = mpd.getTargetAttribute();
            List<InjectDefinition> cascadeInjectInfos = injectInfos;
            for (InjectDefinition injectInfo : cascadeInjectInfos) {
                String attribute = injectInfo.getAttribute();
                if (attribute.contains(".") && attribute.substring(0, attribute.indexOf(".")).equals(targetAttribute)) {
                    cascadeInjectInfos.add(new InjectDefinition(attribute.substring(attribute.indexOf(".") + 1), injectInfo.getInjectMode(), injectInfo.getSource()));
                }
            }
            return composite.handle(returnType, originGetterValue, cascadeIgnoreProperties.toArray(new String[0]), cascadeInjectInfos);
        }
        return null;
    }
}
